package com.UdpRecieve.secret.service.impl;


import com.UdpRecieve.secret.domain.SecretLableResult;
import com.UdpRecieve.secret.log.BussinessUtils;
import com.UdpRecieve.secret.service.SecretBusinessLogicInterface;
import com.UdpRecieve.tool.Global;
import com.UdpRecieve.secret.utils.SECRECT_SBR;
import com.UdpRecieve.secret.log.BianjieLogUtils;
import com.UdpRecieve.tool.SpringUtils;
import com.UdpRecieve.domain.FileOption;
import com.UdpRecieve.domain.FilePigeonhole;
import com.UdpRecieve.mapper.FileOptionMapper;
import com.UdpRecieve.mapper.FilePigeonholeMapper;
import com.UdpRecieve.tool.*;
import com.UdpRecieve.utils.FileUtiles;
import com.UdpRecieve.utils.FileZipNew;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.regex.Matcher;

/**
 * 盛博睿-内网-(单机版/新网络版)-文件归档类
 */
@Component
public class SecretBusinessLogic_SBR_618 implements SecretBusinessLogicInterface {

    FileOptionMapper fileOptionMapper = SpringUtils.getBean(FileOptionMapper.class);

    FilePigeonholeMapper filePigeonholeMapper = SpringUtils.getBean(FilePigeonholeMapper.class);

    private BussinessUtils bussinessUtils = new BussinessUtils();

    private String saveRoot = null;
    private String fileSinglePath = null;
    private String copyPath = null;

    private String fileSecretName = null;
    private String fileSourceName = null;



    private static Logger logger = LoggerFactory.getLogger(SecretBusinessLogic_SBR_618.class);


    /**
     * 注：
     * 1.从梦凡传过来的压缩包中多一层
     * 2.发送 完整性校验 和 验标解标 都是从一个接口 system/prepositive 去大边界
     * 3.描述文件不用了
     * 4.不使用文件编号
     * 5.传给双旭的文件对象,不是json串
     * 业务相关:
     * 1.赘述(边界使用): 用审批时间 + 文件名称去做
     * 2.压缩包失败、md5失败----》都算md5验证失败,发文件对象过去(对象里包含文件名List<String>)
     * 3.发送md5成功就是成功字样,失败就是原因
     *
     * @param filePigeonhole 传输的文件对象
     *                       1.fileType有点
     *                       2.梦凡传过来的（自动和手动）名称是都有加标字样的
     *                       3.标志类型为内部或公开中文（自动和手动）
     *                       4.新增List<String> fileNames 压缩包里的文件名
     * @param resultSave     文件通过netty落地结果
     */
    @Override
    public void saveFile(FilePigeonhole filePigeonhole, String resultSave) {
        SecretLableResult secretLableResult = new SecretLableResult();//结果对象初始化
        List<FileOption> fileOptions = fileOptionMapper.selectFileOptionList(null);
        //下载文件路径(加标文件路径)
        saveRoot = fileOptions.get(0).getFileSaveRoot();
        //单导路径
        fileSinglePath = fileOptions.get(0).getSingleChannelPath();
        //拷贝
        copyPath = fileOptions.get(0).getIllegalPath();


        //当前时间
        Date now = new Date();
        //TODO 如果落地没成功记录日志
        if (!resultSave.equals("成功")) {
            secretLableResult.setErrorMsg("文件落地失败!");
            //存储业务日志-落地日志
            bussinessUtils.save618Zip(filePigeonhole,secretLableResult,now);
            //发送日志给大边界
            BianjieLogUtils.sendFileContentForBigBoundaryM(filePigeonhole,secretLableResult);
            return;
        }else{
            secretLableResult.setSave_result(true);
        }



        //TODO 获取真实文件名,因为从审批过来的文件名是(文件名_加标.后缀),转换成不加后缀的
        String fileName = filePigeonhole.getFileName();
        fileSecretName = filePigeonhole.getFileName();//加标文件名.后缀
        fileSourceName = fileName;//源文件名.后缀
        String uuid = UUID.randomUUID().toString();

        //判断是不是压缩包
        if (filePigeonhole.getFileType().equals(".zip")) {
            try {
                //TODO 把加密文件解压到指定文件夹
                String inputFilePath = saveRoot + File.separator + fileName;//输入路径
                String outputFilePath = saveRoot + File.separator + uuid;//输出路径//audit by cq
                //解压文件到saveRoot下
                FileZipNew.doDecompress(new File(inputFilePath),new File(outputFilePath));
                //删除文件
                FileUtil.deleteFile(inputFilePath);
                File file = new File(outputFilePath);
                File[] files = file.listFiles();
                for (File f:files){
                    if(f.isDirectory()){//文件夹
                        List<String> fileNames = new ArrayList<>();
                        int count = FileUtiles.getFileNames(fileNames,f).size();
                        //TODO 对文件夹重名
                        //重置接收人
                        String getNameZip = filePigeonhole.getGetName();
                        //把接受方中多级的用-连接,以便后边拼接文件夹名称用
                        if (getNameZip.contains("\\")) {
                            getNameZip = getNameZip.replaceAll("\\\\", "-");
                        } else if (getNameZip.contains("/")) {
                            getNameZip = getNameZip.replaceAll("/", "-");
                        }
                        //重置解压路径（文件名<原>_接收方1级-接收方2级_文件数量）
                        System.out.println(f.getParent());
                        String fileZipPATH = f.getParent() + File.separator + f.getName().split("_")[1] + "_" + getNameZip + "_" + count;

                        //对解压后的文件夹遍历解标
                        long startTime = System.currentTimeMillis();
                        while (!f.renameTo(new File(fileZipPATH))){
                            long endTime = System.currentTimeMillis();
                            if ((endTime-startTime)>100000){
                                break;
                            }
                        }
                        unlockSecurt(fileZipPATH,filePigeonhole,secretLableResult,uuid);
                    }else{//文件
                        //设置文件全路径(文件路径+文件名)
                        filePigeonhole.setFilePath(f.getPath());
                        filePigeonhole.setFileName(f.getName());
                        filePigeonhole.setFileType(f.getName().split("\\.")[1]);
                        secretLogic(filePigeonhole,secretLableResult,uuid);
                    }
                }

                //TODO 删除处理好的文件
                //FileUtil.deleteFile(inputFilePath);
            } catch (Exception e) {
                //存储业务日志
                logger.info("压缩包,解压失败,无法进行批量验解标!");
                e.printStackTrace();
            }

        } else {//非压缩包
            //设置文件全路径(文件路径+文件名)
            filePigeonhole.setFilePath(saveRoot + File.separator + fileName);
            secretLogic(filePigeonhole,secretLableResult,null);
        }
    }


    /**
     *  描述:遍历文件夹
     *  如果是文件,就执行验+解标逻辑
     *  如果是文件夹,就递归
     * @param fileNameP           重置解压路径（文件名<原>_接收方1级-接收方2级_文件数量）
     * @param filePigeonhole      文件对象
     * @param secretLableResult   日志结果对象
     */
    private void unlockSecurt(String fileNameP, FilePigeonhole filePigeonhole,SecretLableResult secretLableResult,String uuid) {

        File file = new File(fileNameP);
        if (!file.exists()) {
            logger.info("需要解标的文件夹不存在!"+file.getPath());
        }
        File[] fileNameList = file.listFiles();
        //遍历文件夹,并验标+解标
        for (File f : fileNameList) {
            if (!f.isDirectory()) {//文件
                //重置文件属性
                FilePigeonhole fp = filePigeonhole;
                fp.setFileName(f.getName());//文件名
                fp.setFileType(f.getName().split("\\.")[1]);//.后缀
                fp.setFilePath(f.getPath());//文件全路径
                //进行验+解标逻辑
                secretLogic02(fp,secretLableResult,uuid);
            } else {//文件夹
                //递归
                unlockSecurt(f.getPath(), filePigeonhole,secretLableResult,uuid);
            }
        }

    }


    /**
     * 对文件进行实际的解标和验标逻辑
     * 描述:
     * 1.存储归档对象到数据库
     * 2.存储业务日志-文件落地
     * 3.文件验标
     * 4.存储验标日志,如果失败就发送日志到大边界并结束
     * 5.文件解标
     * 6.文件拷贝-单导用
     * 7.存储解标日志并发送,如果失败就发送日志到大边界并结束
     * 8.依据需求,生成描述文件txt
     *
     * @param filePigeonhole 文件对象
     */
    public void secretLogic02(FilePigeonhole filePigeonhole,SecretLableResult secretLableResult,String uuid) {
        Date now = new Date();//当前时间(统一用一个时间)
        System.out.println("开始验标"+System.currentTimeMillis());
        //TODO 文件验标
        try {
            //验标
            secretLableResult  = SECRECT_SBR.CheckStancdard(filePigeonhole.getFilePath(), filePigeonhole,secretLableResult);
            filePigeonhole.setApproverName(secretLableResult.getAuthority());
            filePigeonhole.setSendName(secretLableResult.getDrafter());
            filePigeonhole.setFileSort(secretLableResult.getStatus());
            filePigeonhole.setSecrecyLevel(secretLableResult.getLevel());
            //logger.info("验标结果：" + secretLableResult.getSecret_result());
            if(!secretLableResult.getSecret_result()){
                throw new Exception("验标失败");
            }
        } catch (Exception e) {
            //TODO 验标失败,存储验标本地日志,发送日志给边界
            logger.info("------------------------验标失败!------------------------");
            secretLableResult.setErrorMsg("验标失败");
            //存储验标日志
            bussinessUtils.save(filePigeonhole, secretLableResult, now);
            //发送日志到大边界
            BianjieLogUtils.sendFileContentForBigBoundaryM(filePigeonhole,secretLableResult);
            e.printStackTrace();
            return;
        }

        //System.out.println("开始解标"+System.currentTimeMillis());
        //TODO 文件解标
        try {
            Boolean StandardSubtraction = null;//解标结果初始化
            //备份
            String copyOutPath = filePigeonhole.getFilePath().replace(saveRoot,copyPath);
            copyOutPath = copyOutPath.replace(uuid,filePigeonhole.getGetName());
            File filec = new File(copyOutPath);
            File fileP = new File(filec.getParent());
            if (!fileP.exists()){
                fileP.mkdirs();
            }
            Files.copy(Paths.get(filePigeonhole.getFilePath()), Paths.get(copyOutPath), StandardCopyOption.REPLACE_EXISTING);
            //进行原地解标
            StandardSubtraction = SECRECT_SBR.StandardSubtraction(filePigeonhole.getFilePath());
            secretLableResult.setSecret_solve_result(StandardSubtraction);
            //logger.info("解标结果：" + StandardSubtraction);
            File file = new File(filePigeonhole.getFilePath());
            String md5 = MD5FileUtils.getMD5(file);
            filePigeonhole.setMd5CheckNum(md5);
        } catch (Exception e) {
            //TODO 文件解标失败,存储本地解标日志,发送日志到边界
            logger.info("------------------------解标失败!------------------------");
            //存储本地日志
            bussinessUtils.save(filePigeonhole, secretLableResult,now);
            //发送总日志给大边界
            BianjieLogUtils.sendFileContentForBigBoundaryM(filePigeonhole,secretLableResult);
            e.printStackTrace();
            return;
        }
        //System.out.println("开始拷贝"+System.currentTimeMillis());
        //TODO 文件拷贝-单导用
        String ZipFileTemp = Global.getConfig("unCompressionFileName");//解压中间文件夹
        //拼接单导路径
        String fileSinglePathZip = fileSinglePath + File.separator + ZipFileTemp;
        try {
            //logger.info("移动文件到单导发送目录");
            String fileSourcePathAll = filePigeonhole.getFilePath();
            String fileCopyPathAll = (fileSourcePathAll.replace(saveRoot, fileSinglePathZip)).replaceAll(uuid,"");

            //确保文件夹存在
            File fisOk = new File(fileCopyPathAll);
            File filePOk = new File(fisOk.getParent());
            if (!filePOk.exists()) {
                filePOk.mkdirs();
            }
            //移动文件，存在就覆盖
            Files.move(Paths.get(fileSourcePathAll), Paths.get(fileCopyPathAll), StandardCopyOption.REPLACE_EXISTING);
            secretLableResult.setCopy_single(true);
            //logger.info("文件成功移动到单导目录");
        } catch (Exception e) {
            logger.info("文件没有成功移动到单导目录");
            e.printStackTrace();
            //存储业务日志-拷贝
            bussinessUtils.save(filePigeonhole,secretLableResult, now);//5-文件拷贝到单导目录失败
            return;
        }

        //TODO 存储最终日志
        //发送总日志给大边界
        BianjieLogUtils.sendFileContentForBigBoundaryM(filePigeonhole,secretLableResult);
        //存储本地日志
        bussinessUtils.save(filePigeonhole, secretLableResult,now);
        //TODO 存储归档对象到数据库
        //封装完整归档对象（封装后,文件名是解标后的文件名）
        filePigeonhole = bussinessUtils.installationF(filePigeonhole, null, null, now);
        //存储归档对象到数据库
        filePigeonholeMapper.insertFilePigeonhole(filePigeonhole);
    }


    /**
     * 对文件进行实际的解标和验标逻辑
     * 描述:
     * 1.存储归档对象到数据库
     * 2.存储业务日志-文件落地
     * 3.文件验标
     * 4.存储验标日志,如果失败就发送日志到大边界并结束
     * 5.文件解标
     * 6.文件拷贝-单导用
     * 7.存储解标日志并发送,如果失败就发送日志到大边界并结束
     * 8.依据需求,生成描述文件txt
     *
     * @param filePigeonhole 文件对象
     */
    public void secretLogic(FilePigeonhole filePigeonhole,SecretLableResult secretLableResult,String uuid) {
        Date now = new Date();//当前时间(统一用一个时间)
        //TODO 文件验标
        System.out.println("开始验标"+System.currentTimeMillis());
        try {
            secretLableResult = SECRECT_SBR.CheckStancdard(filePigeonhole.getFilePath(),filePigeonhole,secretLableResult);
            //logger.info("验标结果：" + secretLableResult.getSecret_result());
            secretLableResult.setSecret_result(secretLableResult.getSecret_result());
            filePigeonhole.setApproverName(secretLableResult.getAuthority());
            filePigeonhole.setSendName(secretLableResult.getDrafter());
            filePigeonhole.setFileSort(secretLableResult.getStatus());
            filePigeonhole.setSecrecyLevel(secretLableResult.getLevel());

            if(!secretLableResult.getSecret_result()){
                throw new Exception("验标失败");
            }
        } catch (Exception e) {
            logger.info("------------------------验标失败!------------------------");
            secretLableResult.setErrorMsg("验标失败");
            //存储本地日志
            bussinessUtils.save(filePigeonhole,secretLableResult, now);
            //发送日志到大边界
            BianjieLogUtils.sendFileContentForBigBoundaryM(filePigeonhole,secretLableResult);
            e.printStackTrace();
            return;
        }
        System.out.println("开始解标"+System.currentTimeMillis());
        //TODO 文件解标
        try {
            //备份
            String copyOutPath = filePigeonhole.getFilePath().replace(saveRoot,copyPath);
            if (uuid!=null){
                copyOutPath = copyOutPath.replace(uuid,filePigeonhole.getGetName());
            }
            File filec = new File(copyOutPath);
            File fileP = new File(filec.getParent());
            if (!fileP.exists()){
                fileP.mkdirs();
            }
            Files.copy(Paths.get(filePigeonhole.getFilePath()), Paths.get(copyOutPath), StandardCopyOption.REPLACE_EXISTING);

            Boolean StandardSubtraction = null;
            //进行原地解标
            StandardSubtraction = SECRECT_SBR.StandardSubtraction(filePigeonhole.getFilePath());
            //logger.info("解标结果：" + StandardSubtraction);
            secretLableResult.setSecret_solve_result(true);
            File file = new File(filePigeonhole.getFilePath());
            String md5 = MD5FileUtils.getMD5(file);
            filePigeonhole.setMd5CheckNum(md5);
        } catch (Exception e) {
            //logger.info("------------------------解标失败!------------------------");
            //存储业务日志-解标
            bussinessUtils.save(filePigeonhole, secretLableResult, now);
            //发送总日志给大边界
            BianjieLogUtils.sendFileContentForBigBoundaryM(filePigeonhole, secretLableResult);
            //抛出异常
            e.printStackTrace();
            return;
        }
        System.out.println("开始拷贝"+System.currentTimeMillis());

        //TODO 文件拷贝-单导用
        String getName = filePigeonhole.getGetName();//接受方
        //拼接单导路径
        String fileSinglePathAndGetName = fileSinglePath + File.separator + getName;
        try {
            //logger.info("拷贝文件到单导发送目录");
            String fileSourcePath = filePigeonhole.getFilePath();
            String fileCopyPath = fileSinglePathAndGetName + File.separator + filePigeonhole.getFileName();
            File fisOk = new File(fileSinglePathAndGetName);
            //确保拷贝后的文件夹存在
            if (!fisOk.exists()) {
                fisOk.mkdirs();
            }
            //移动文件，存在就覆盖
            Files.move(Paths.get(fileSourcePath), Paths.get(fileCopyPath), StandardCopyOption.REPLACE_EXISTING);
            secretLableResult.setCopy_single(true);
            //logger.info("文件成功移动到单导目录");
        } catch (Exception e) {
            //logger.info("文件没有成功移动到单导目录");
            //存储业务日志-拷贝
            bussinessUtils.save(filePigeonhole, secretLableResult, now);
            e.printStackTrace();
            return;
        }


        //TODO 存储最终日志
        BianjieLogUtils.sendFileContentForBigBoundaryM(filePigeonhole, secretLableResult);
        bussinessUtils.save(filePigeonhole, secretLableResult, now);

        //TODO 存储文件归档日志
        //封装完整归档对象（封装后,文件名是解标后的文件名）
        filePigeonhole = bussinessUtils.installationF(filePigeonhole, null, null, now);
        filePigeonholeMapper.insertFilePigeonhole(filePigeonhole);

    }


}
